#include "gui.hpp"
#include <iostream>

		Gui::Gui(Judge *dreferee, std::bitset<1444> *m) : width(760), height(800), gridx(9), gridy(9), fps(30), map(m), singleplayer(true), replay(true), header(40)
{
    window = new sf::RenderWindow(sf::VideoMode(width, height), "Gomoku");
	window->setFramerateLimit(this->fps);
	referee = dreferee;
	player = dreferee->playerTurn();
	this->loadTexture(BACKGROUND, "../Ressources/bg_start.png");
	this->loadTexture(BLACK, "../Ressources/player1.png");
	this->loadTexture(WHITE, "../Ressources/player2.png");
	this->loadTexture(GRID, "../Ressources/grid.png");
	this->loadTexture(HOVER, "../Ressources/hovergrid.png");
	this->loadTexture(P1WIN, "../Ressources/p1wins.png");
	this->loadTexture(P2WIN, "../Ressources/p2wins.png");
	this->loadText(SINGLEPLAYER, "1 player");
	this->loadText(MULTIPLAYER, "2 players");
	this->loadText(REPLAY, "Rejouer");
	this->loadText(QUIT, "Quitter");
}

		Gui::~Gui()
{

}

void	Gui::addPawn()
{
	if (this->gridx < 0 || this->gridx > 19 || this->gridy < 1 || this->gridy > 20)
		std::cout << "pawn out of boudaries" << this->player << "[" << this->gridx << ":" << this->gridy - 1 << "]" << std::endl;
	else
	{
		if (this->referee->play(this->player, this->gridx, this->gridy - 1))
			std::cout << "pawn added : " << this->player << "[" << this->gridx << ":" << this->gridy - 1 << "]" << std::endl;
		else
			std::cout << "forbidden movement : " << this->player << "[" << this->gridx << ":" << this->gridy - 1 << "]" << std::endl;
		this->player = this->referee->playerTurn();
	}
}

void	Gui::handleGameEvents()
{
	sf::Event event;
    while (this->window->pollEvent(event))
    {
        if (event.type == sf::Event::Closed)
            this->window->close();
		if (event.type == sf::Event::MouseMoved)
		{
			this->gridx = event.mouseMove.x / 40;
			this->gridy = event.mouseMove.y / 40;
		}
		if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left)
			this->addPawn();
		if (event.type == sf::Event::KeyPressed)
		{
			if (event.key.code == sf::Keyboard::Escape)
				this->window->close();
			if (event.key.code == sf::Keyboard::Right && this->gridx < 18)
				++this->gridx;
			if (event.key.code == sf::Keyboard::Left && this->gridx > 0)
				--this->gridx;
			if (event.key.code == sf::Keyboard::Down && this->gridy < 19)
				++this->gridy;
			if (event.key.code == sf::Keyboard::Up && this->gridy > 1)
				--this->gridy;
			if (event.key.code == sf::Keyboard::Space || event.key.code == sf::Keyboard::Return)
				this->addPawn();
		}
    }
}

void	Gui::handleEndEvents()
{
	sf::Event event;
    while (this->window->pollEvent(event))
    {
         if (event.type == sf::Event::Closed)
            this->window->close();
		if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
			this->window->close();
		if (event.type == sf::Event::KeyPressed)
		{
			if (event.key.code == sf::Keyboard::Return)
			{
				if (this->replay == true)
				{
					this->referee->resetGame();
					this->loop();
				}
				else
					this->window->close();
			}
			if (event.key.code == sf::Keyboard::Up)
				this->replay = true;
			if (event.key.code == sf::Keyboard::Down)
				this->replay = false;
		}
		if (event.type == sf::Event::MouseMoved)
		{
			this->mousex = event.mouseMove.x;
			this->mousey = event.mouseMove.y;
			if (this->collides(REPLAY))
				this->replay = true;
			if (this->collides(QUIT))
				this->replay = false;
		}
		if (event.type == sf::Event::MouseButtonReleased)
		{
			if (this->collides(REPLAY))
			{
				this->referee->resetGame();
				this->loop();
			}
			if (this->collides(QUIT))
				this->window->close();
		}
    }
}

void	Gui::handleModeEvents()
{
	sf::Event event;
    while (this->window->pollEvent(event))
    {
        if (event.type == sf::Event::Closed)
            this->window->close();
		if (event.type == sf::Event::KeyPressed)
		{
			if (event.key.code == sf::Keyboard::Return)
				this->loop();
			if (event.key.code == sf::Keyboard::Up)
				this->singleplayer = true;
			if (event.key.code == sf::Keyboard::Down)
				this->singleplayer = false;
			if (event.key.code == sf::Keyboard::Escape)
				this->window->close();
		}
		if (event.type == sf::Event::MouseMoved)
		{
			this->mousex = event.mouseMove.x;
			this->mousey = event.mouseMove.y;
			if (this->collides(SINGLEPLAYER))
				this->singleplayer = true;
			if (this->collides(MULTIPLAYER))
				this->singleplayer = false;
		}
		if (event.type == sf::Event::MouseButtonReleased)
			this->loop();
    }
}



void	Gui::loadTexture(int id, char *file)
{
	textures[id].loadFromFile(file);
	sprites[id].setTexture(textures[id]);
}

void	Gui::loadText(int id, std::string string)
{
	this->texts[id].setString(string);
}

bool	Gui::collides(int id)
{

	sf::FloatRect item(this->texts[id].getGlobalBounds());
	sf::Vector2f mouse(this->mousex, this->mousey);

	return item.contains(mouse);
}

void	Gui::checkEnd()
{
	int	win;

	win = this->referee->getWinner();
	if (win >= 0)
	{
		std::cout << "END" << std::endl;
		this->texts[REPLAY].setPosition(350, 500);
		this->texts[QUIT].setPosition(350,550);
		this->sprites[WHITE].setPosition(300, 500);
		this->sprites[BLACK].setPosition(300, 550);
		while(this->window->isOpen())
		{
			this->handleEndEvents();
			this->window->draw(this->sprites[P1WIN + win]);
			this->window->draw(this->texts[REPLAY]);
			this->window->draw(this->texts[QUIT]);
			if (this->replay)
				this->window->draw(this->sprites[WHITE]);
			else
				this->window->draw(this->sprites[BLACK]);
			this->window->display();
		}
	}
}

void	Gui::drawPawns()
{
	float	x, y;
	int		i;
	
	std::bitset<1444> blanc = std::bitset<1444>(std::string("0010"));
	std::bitset<1444> noir = std::bitset<1444>(std::string("0100"));
	y = 0;
	i = 0;

	while (i < 1444)
	{
		x = 0;
		while(x < 19)
		{
			if ((blanc & *map >> i) == blanc)
			{
				this->sprites[WHITE].setPosition(x * 40, y * 40 + header);
				this->window->draw(this->sprites[WHITE]);
			}
			else if ((noir & *map >> i) == noir)
			{
				this->sprites[BLACK].setPosition(x * 40, y * 40 + header);
				this->window->draw(this->sprites[BLACK]);
			}
			++x;
			i+=4;
		}
		++y;
	}
}

void	Gui::drawGrid()
{
	float		tx, ty;

	tx = (float)this->textures[HOVER].getSize().x;
	ty = (float)this->textures[HOVER].getSize().y;
	this->sprites[GRID].setPosition(0, 40);
	this->window->draw(this->sprites[GRID]);
	if (this->gridy > 0 && this->gridy < 20)
	{
		this->sprites[HOVER].setPosition(this->gridx*tx, this->gridy*ty);
		this->window->draw(this->sprites[HOVER]);
	}
}

void	Gui::drawBackground()
{
	float	x, y;
	int		tx, ty;
	tx = this->textures[BACKGROUND].getSize().x;
	ty = this->textures[BACKGROUND].getSize().y;
	x = 0;
	while(x < this->width)
	{
		y = 0;
		while(y < this->height)
		{
			this->sprites[BACKGROUND].setPosition(x, y);
			this->window->draw(this->sprites[BACKGROUND]);
			y += ty;
		}
		x += tx;
	}
}

void	Gui::drawScores()
{
	int			*scores;
	std::ostringstream white;
	std::ostringstream black;

	scores = this->referee->getScores();

	white << scores[WHITE];
	black << scores[BLACK];
	this->texts[SCOREWHITE].setString(white.str());
	this->texts[SCOREBLACK].setString(black.str());


	this->sprites[WHITE].setPosition(0,0);
	this->sprites[BLACK].setPosition(720,0);
	this->texts[SCOREWHITE].setPosition(50, 0);
	this->texts[SCOREBLACK].setPosition(690, 0);
	this->window->draw(this->texts[SCOREWHITE]);
	this->window->draw(this->texts[SCOREBLACK]);
	this->window->draw(this->sprites[WHITE]);
	this->window->draw(this->sprites[BLACK]);
	this->sprites[player-1].setPosition(350,0);
	this->window->draw(this->sprites[player -1]);
}

int		Gui::selectMode()
{
	this->texts[SINGLEPLAYER].setPosition(280, 500);
	this->texts[MULTIPLAYER].setPosition(280,550);
	Animation anim;
	anim.initSelectMode(this->fps);
    while (this->window->isOpen())
    {
		this->handleModeEvents();
		this->drawBackground();
		if (this->singleplayer)
		{
			this->sprites[WHITE].setPosition(230, 500);
			this->window->draw(this->sprites[WHITE]);
		}
		else
		{
			this->sprites[BLACK].setPosition(230, 550);
			this->window->draw(this->sprites[BLACK]);
		}
		this->window->draw(this->texts[SINGLEPLAYER]);
		this->window->draw(this->texts[MULTIPLAYER]);
		anim.runSelectMode(this->window);
		this->window->display();
    }
	return 0;
}


void	Gui::runPlayer()
{

}

void	Gui::runIA()
{
	/*
	** IA (+ heuristique ?)
	**
	**
	**  this->referee->ia();
	*/

	// crap pour tester :
	this->IAx = std::rand() % 19;
	this->IAy = std::rand() % 19;
	this->referee->play(2, this->IAx, this->IAy);
	// /crap
	
	this->player = this->referee->playerTurn();
}

int		Gui::loop()
{
	 
    while (this->window->isOpen())
    {
		this->window->clear();
		if (this->singleplayer && this->player == 2)
			this->runIA();
		else
	        this->handleGameEvents();
		this->drawGrid();
		this->drawPawns();
		this->drawScores();
        this->window->display();
		this->checkEnd();
    }
	return 0;
}